home *** CD-ROM | disk | FTP | other *** search
/ Over 1,000 Windows 95 Programs / Over 1000 Windows 95 Programs (Microforum) (Disc 1).iso / 1249 / root.t < prev    next >
Text File  |  1997-04-18  |  34KB  |  1,681 lines

  1. %
  2. % "root.t" demonstates techniques for the numerical 
  3. % solution of non-linear equations
  4. %
  5. %   Sample program for the T Interpreter by:
  6. %
  7. %   Stephen R. Schmitt
  8. %   962 Depot Road
  9. %   Boxborough, MA 01719
  10. %
  11.  
  12. const MATVECT_EPSILON : real := 1.0E-15
  13. const TOLERANCE : real := 0.00000001
  14. const MAX_ITER : int := 50
  15. const DIM : int := 10
  16.  
  17. type rvector : array[DIM] of real
  18. type ivector : array[DIM] of int
  19. type rmatrix : array[DIM,DIM] of real
  20.  
  21. type complex : record
  22.  
  23.                re : real
  24.                im : real
  25.  
  26.                end record
  27.  
  28. type cvector : array[DIM] of complex
  29.  
  30.  
  31. program
  32.  
  33.     do_bisection
  34.     do_newton_approx
  35.     do_newton_exact
  36.     do_richmond_approx
  37.     do_richmond_exact
  38.     do_combined
  39.     do_brent
  40.     do_deflation
  41.     do_lin_bairstow
  42.     do_newton_two_fncs
  43.     do_newton_multi_roots
  44.     do_newton_snle
  45.     
  46. end program
  47.  
  48. %---------------------------------------------------------------------
  49. % demonstrations of the numerical solution of non-linear equations
  50. %---------------------------------------------------------------------
  51.  
  52. %
  53. % Fx    returns the value of:          f(x)  = exp(x) - 3*x^2
  54. %
  55. % d_Fx  returns the first derivative:  f'(x) = exp(x) - 6*x
  56. %
  57. % dd_Fx returns the second derivative: f"(x) = exp(x) - 6
  58. %
  59. function Fx( x : real ) : real
  60.  
  61.     return exp(x) - 3*x^2
  62.  
  63. end function
  64.  
  65. function d_Fx( x : real ) : real
  66.  
  67.     return exp(x) - 6*x
  68.  
  69. end function
  70.  
  71. function dd_Fx( x : real ) : real
  72.  
  73.     return exp(x) - 6
  74.  
  75. end function
  76.  
  77. const Fx_msg : string := "solving: f(x) = exp(x) - 3*x^2"
  78.  
  79. %
  80. % returns value of either of two sumultaneous non-linear equations:
  81. %
  82. %   f0(x0,x1) = x1*exp(x0) - 2
  83. %   f1(x0,x1) = x0^2 + x1 - 4
  84. %
  85. function Snle( var x : rvector, index : int ) : real
  86.   
  87.     case index of
  88.     
  89.         value 0:
  90.             return x[1] * exp( x[0] ) - 2
  91.  
  92.         value 1:
  93.             return x[0]^2 + x[1] - 4
  94.  
  95.         value:
  96.             return 1
  97.   
  98.     end case
  99.     
  100. end function
  101.  
  102. const f0_msg : string := "f0(x0,x1) = x1*exp(x0) - 2"
  103.  
  104. const f1_msg : string := "f1(x0,x1) = x0^2 + x1 - 4"
  105.  
  106. %
  107. % F1xy returns the value of: f1(x,y) = x^2 + y^2 - 1
  108. %
  109. % F2xy returns the value of: f2(x,y) = x^2 - y^2 + 0.5
  110. %
  111. function F1xy( x, y : real ) : real
  112.  
  113.   return x^2 + y^2 - 1
  114.  
  115. end function
  116.  
  117. function F2xy( x, y : real ) : real
  118.  
  119.   return x^2 - y^2 + 0.5
  120.   
  121. end function
  122.  
  123. const F1xy_msg : string := "f1(x,y) = x^2 + y^2 - 1"
  124.  
  125. const F2xy_msg : string := "f2(x,y) = x^2 - y^2 + 0.5"
  126.  
  127. %
  128. % test Bisection
  129. %
  130. procedure do_bisection
  131.  
  132.     var low, high, root : real
  133.  
  134.     low := 2
  135.     high := 4
  136.  
  137.     put "bisection method\n"
  138.     put Fx_msg 
  139.     put "guess interval is: ", low, "...", high
  140.  
  141.     if Bisection( low, high, root ) then
  142.  
  143.         put "root = ", root
  144.  
  145.     else
  146.  
  147.         put "could not solve"
  148.  
  149.     end if
  150.  
  151. end procedure
  152.  
  153. %
  154. % test Newton_approx
  155. %
  156. procedure do_newton_approx
  157.  
  158.     var root : real := 3
  159.     var num_roots, i : int
  160.  
  161.     put "\nNewton's method for an approximate derivative\n"
  162.     put Fx_msg
  163.     put "initial guess is: ", root
  164.     
  165.     if Newton_approx( root ) then
  166.         
  167.         put "root = ", root
  168.  
  169.     else
  170.  
  171.         put "could not solve"
  172.  
  173.     end if
  174.     
  175. end procedure
  176.  
  177. %
  178. % test Newton_exact
  179. %
  180. procedure do_newton_exact
  181.  
  182.     var root : real := 3
  183.  
  184.     put "\nNewton's method for a user provided derivative\n"
  185.     put Fx_msg
  186.     put "initial guess is: ", root
  187.     
  188.     if Newton_exact( root ) then
  189.         
  190.         put "root = ", root
  191.  
  192.     else
  193.  
  194.         put "could not solve"
  195.  
  196.     end if
  197.     
  198. end procedure
  199.  
  200. %
  201. % test Richmond_approx
  202. %
  203. procedure do_richmond_approx
  204.  
  205.     var root : real := 3
  206.  
  207.     put "\nRichmond's method with an approximate derivative\n"
  208.     put Fx_msg
  209.     put "initial guess is: ", root
  210.  
  211.     if Richmond_approx( root ) then
  212.  
  213.         put "root = ", root
  214.  
  215.     else
  216.  
  217.         put "could not solve"
  218.  
  219.     end if
  220.     
  221. end procedure
  222.  
  223. %
  224. % test Richmond_exact
  225. %
  226. procedure do_richmond_exact
  227.  
  228.     var root : real := 3
  229.  
  230.     put "\nRichmond's method with a user provided derivative\n"
  231.     put Fx_msg
  232.     put "initial guess is: ", root
  233.  
  234.     if Richmond_exact( root ) then
  235.  
  236.         put "root = ", root
  237.  
  238.     else
  239.  
  240.         put "could not solve"
  241.  
  242.     end if
  243.     
  244. end procedure
  245.  
  246. %
  247. % test Combined
  248. %
  249. procedure do_combined
  250.  
  251.     var low, high, root : real
  252.  
  253.     low := 2
  254.     high := 4
  255.  
  256.     put "\nCombined method\n"
  257.     put Fx_msg
  258.     put "guess interval is: ", low, "...", high
  259.  
  260.     if Combined( low, high, root ) then
  261.  
  262.         put "root = ", root
  263.  
  264.     else
  265.  
  266.         put "could not solve"
  267.  
  268.     end if
  269.     
  270. end procedure
  271.  
  272. %
  273. % test Brent
  274. %
  275. procedure do_brent
  276.  
  277.     var low, high, root : real
  278.  
  279.     low := 2
  280.     high := 4
  281.  
  282.     put "\nBrent's method\n"
  283.     put Fx_msg 
  284.     put "guess interval is: ", low, "...", high
  285.  
  286.     if Brent( low, high, root ) then
  287.  
  288.         put "root = ", root
  289.  
  290.     else
  291.  
  292.         put "could not solve"
  293.  
  294.     end if
  295.     
  296. end procedure
  297.  
  298. %
  299. % test Deflate_polynomial
  300. %
  301. procedure do_deflation
  302.  
  303.     const SMALL : real := 0.00000001
  304.     var coeff, roots : rvector
  305.     var poly_order, num_roots, i : int
  306.  
  307.     poly_order := 3
  308.     coeff[0] := -40
  309.     coeff[1] :=  62
  310.     coeff[2] := -23
  311.     coeff[3] :=   1
  312.  
  313.     put "\nDeflating Polynomial method\n"
  314.  
  315.     put "the polynomial:"
  316.     for decreasing i := poly_order...0 do
  317.  
  318.         if i > 1 then
  319.  
  320.             put coeff[i], "*X^", i, " + "...
  321.  
  322.         elsif i = 1 then
  323.  
  324.             put coeff[i], "*X + "...
  325.  
  326.         elsif i = 0 then
  327.  
  328.             put coeff[i]...
  329.  
  330.         end if
  331.  
  332.     end for
  333.  
  334.     put " = 0"
  335.  
  336.     if Deflate_polynomial( coeff, 1.1, roots, 
  337.                          num_roots, poly_order ) then
  338.  
  339.         put "has roots:"
  340.         for i := 0...poly_order-1 do
  341.  
  342.             put "root ", i + 1, " = ", roots[i]
  343.  
  344.  
  345.         end for
  346.             
  347.     else
  348.  
  349.         put "could not solve"
  350.  
  351.     end if
  352.     
  353. end procedure
  354.  
  355. %
  356. % test Lin_Bairstow
  357. %
  358. procedure do_lin_bairstow
  359.  
  360.     var coeff : rvector
  361.     var roots : cvector
  362.     var r : complex
  363.     var num_roots, poly_order, i : int
  364.  
  365.     poly_order := 3
  366.     coeff[0] :=   8
  367.     coeff[1] :=   4
  368.     coeff[2] :=   2
  369.     coeff[3] :=   1
  370.  
  371.     put "\nLin-Bairstow method\n"
  372.  
  373.     put "the polynomial:"
  374.     for decreasing i := poly_order...0 do
  375.  
  376.         if i > 1 then
  377.  
  378.             put coeff[i], "*X^", i, " + "...
  379.  
  380.         elsif i = 1 then
  381.  
  382.             put coeff[i], "*X + "...
  383.  
  384.         elsif i = 0 then
  385.  
  386.             put coeff[i]...
  387.  
  388.         end if
  389.  
  390.     end for
  391.  
  392.     put " = 0"
  393.  
  394.     if Lin_Bairstow( coeff, roots, poly_order ) then
  395.  
  396.         put "has roots:"
  397.         for i := 0...poly_order-1 do
  398.  
  399.             r.re := roots[i].re
  400.             r.im := roots[i].im
  401.             put cstr( r )
  402.  
  403.         end for
  404.             
  405.     else
  406.  
  407.         put "could not solve"
  408.  
  409.     end if
  410.     
  411. end procedure
  412.  
  413. %
  414. % test Newton2functions
  415. %
  416. procedure do_newton_two_fncs
  417.  
  418.     var rootX, rootY : real
  419.  
  420.     rootX := 1
  421.     rootY := 3
  422.  
  423.     put "\nNewton's method for two equations\n"
  424.     put "solving: "
  425.     put F1xy_msg
  426.     put F2xy_msg
  427.     put "initial guess for x is ", rootX
  428.     put "initial guess for y is ", rootY
  429.  
  430.     if Newton2functions( rootX, rootY ) then
  431.  
  432.         put "root X = ", rootX
  433.         put "root Y = ", rootY
  434.  
  435.     else
  436.  
  437.         put "could not solve"
  438.  
  439.     end if
  440.     
  441. end procedure
  442.  
  443. %
  444. % test NewtonMultiRoots
  445. %
  446. procedure do_newton_multi_roots
  447.  
  448.     var roots : rvector
  449.     var num_roots, i : int
  450.  
  451.     roots[0] := 2
  452.  
  453.     put "\nNewton's method for multiple roots\n"
  454.     put Fx_msg
  455.     put "initial guess is: ", roots[0]
  456.     
  457.     if NewtonMultiRoots( roots, num_roots, DIM ) then
  458.  
  459.         for i := 0...num_roots-1 do
  460.         
  461.             put "root ", i + 1, " = ", roots[i]
  462.  
  463.         end for
  464.  
  465.     else
  466.  
  467.         put "could not solve"
  468.  
  469.     end if
  470.     
  471.  
  472. end procedure
  473.  
  474. %
  475. % test NewtonSimNLE
  476. %
  477. procedure do_newton_snle
  478.  
  479.     var Xguess : rvector
  480.     var num_eqns, i : int
  481.  
  482.     num_eqns := 2
  483.     Xguess[0] := -0.16
  484.     Xguess[1] :=  2.7
  485.  
  486.     put "\nNewton's method for simultaneous non-linear equations\n"
  487.     put "solving for:"
  488.     put f0_msg
  489.     put f1_msg
  490.  
  491.     for i := 0...num_eqns-1 do
  492.  
  493.         put "initial guess for X", i, " = ", Xguess[i]
  494.  
  495.     end for
  496.  
  497.     if NewtonSimNLE( Xguess, num_eqns ) then
  498.  
  499.         put "roots are:"
  500.  
  501.         for i := 0...num_eqns-1 do
  502.  
  503.             put "X", i, " = ", Xguess[i]
  504.  
  505.         end for
  506.  
  507.     else
  508.  
  509.         put "could not solve"
  510.  
  511.     end if
  512.  
  513. end procedure
  514.  
  515. %---------------------------------------------------------------------
  516. % functions for numerical solution of non-linear equations
  517. %---------------------------------------------------------------------
  518.  
  519. %
  520. % Solve for a root of a function of a single variable by selecting
  521. % an initial interval that contains the root and searching
  522. %
  523. function Bisection( low, high : real, var root : real ) : boolean
  524.  
  525.     if Fx( low ) * Fx( high ) > 0 then
  526.     
  527.         return false
  528.  
  529.     end if
  530.  
  531.     loop
  532.     
  533.         exit when abs( high - low ) < TOLERANCE
  534.     
  535.         % update guess
  536.     
  537.         root := ( low + high ) / 2
  538.     
  539.         if Fx( root ) * Fx( high ) > 0 then
  540.       
  541.             high := root
  542.     
  543.         else
  544.       
  545.             low := root
  546.     
  547.         end if
  548.     
  549.     end loop
  550.   
  551.     return true
  552.  
  553. end function
  554.  
  555. %
  556. % Solve for a root of a function of a single variable by selecting
  557. % an initial guess and using the function value and an approximate
  558. % derivative to search for the solution
  559. %
  560. function Newton_approx( var root : real ) : boolean
  561.   
  562.     var iter : int := 0
  563.     var h, diff : real
  564.     
  565.     loop
  566.     
  567.         h := 0.01 * root
  568.         
  569.         if abs( root ) < 1 then 
  570.         
  571.             h := 0.01
  572.  
  573.         end if
  574.         
  575.         % calculate guess refinement
  576.         diff := 2 * h * Fx( root ) 
  577.         diff := diff / ( Fx( root+h ) - Fx( root-h ) )
  578.  
  579.         % update guess
  580.         root := root - diff
  581.         iter := iter + 1
  582.  
  583.         exit when iter > MAX_ITER or abs( diff ) < TOLERANCE
  584.     
  585.     end loop
  586.   
  587.     if abs( diff ) <= TOLERANCE then
  588.         
  589.         return true
  590.         
  591.     else
  592.     
  593.         return false
  594.         
  595.     end if
  596.  
  597. end function
  598.  
  599. %
  600. % Solve for a root of a function of a single variable by selecting
  601. % an initial guess and using the function value and the
  602. % derivative to search for the solution
  603. %
  604. function Newton_exact( var root : real ) : boolean
  605.   
  606.     var iter : int := 0
  607.     var diff : real
  608.  
  609.     loop
  610.     
  611.         % calculate guess refinement
  612.         diff := Fx( root ) / d_Fx( root )
  613.        
  614.         % update guess
  615.         root := root - diff
  616.         iter := iter + 1
  617.  
  618.         exit when iter > MAX_ITER or abs( diff ) < TOLERANCE
  619.  
  620.     end loop
  621.   
  622.     if abs( diff ) <= TOLERANCE then
  623.       
  624.         return true
  625.         
  626.     else
  627.     
  628.         return false
  629.         
  630.     end if
  631.  
  632. end function
  633.  
  634. %
  635. % Solve for a root of a function of a single variable by selecting
  636. % an initial guess and using the function value and an approximation
  637. % of the first and second derivative to search for the solution
  638. %
  639. function Richmond_approx( var root : real ) : boolean
  640.   
  641.     var iter : int
  642.     var h, diff : real
  643.     var f1, f2, f3 : real
  644.     var fd1, fd2 : real
  645.   
  646.     loop
  647.     
  648.         h := 0.01 * root
  649.        
  650.         if abs( root ) < 1 then 
  651.             
  652.             h := 0.01
  653.             
  654.         end if
  655.        
  656.         f1 := Fx( root - h )                    % f(x-h)
  657.         f2 := Fx( root )                        % f(x)
  658.         f3 := Fx( root + h )                    % f(x+h)
  659.         fd1 := ( f3 - f1 ) / ( 2 * h )          % f'(x)
  660.         fd2 := ( f3 - 2 * f2 + f1 ) / sqrt( h ) % f"(x)
  661.        
  662.         % calculate guess refinement
  663.         diff := f1 * fd1 / ( fd1 ^ 2 - 0.5 * f1 * fd2 )
  664.        
  665.         % update guess
  666.         root := root - diff
  667.         iter := iter + 1
  668.  
  669.         exit when iter > MAX_ITER or abs( diff ) < TOLERANCE
  670.  
  671.     end loop
  672.   
  673.     if abs( diff ) <= TOLERANCE then
  674.       
  675.         return true
  676.         
  677.     else
  678.     
  679.         return false
  680.         
  681.     end if
  682.  
  683. end function
  684.  
  685. %
  686. % Solve for a root of a function of a single variable by selecting
  687. % an initial guess and using the function value and an approximation
  688. % of the first and second derivative to search for the solution
  689. %
  690. function Richmond_exact( var root : real ) : boolean
  691.  
  692.     var iter : int
  693.     var diff, f1 : real
  694.     var fd1, fd2 : real
  695.  
  696.     iter := 0
  697.   
  698.     loop
  699.      
  700.         f1 := Fx( root )
  701.         fd1 := d_Fx( root )
  702.         fd2 := dd_Fx( root )
  703.      
  704.         % calculate guess refinement
  705.         diff := f1 * fd1 / ( fd1^2 - 0.5 * f1 * fd2 )
  706.         
  707.         % update guess
  708.         root := root - diff
  709.         iter := iter + 1
  710.  
  711.         exit when iter > MAX_ITER or abs( diff ) < TOLERANCE
  712.  
  713.     end loop
  714.  
  715.     if abs( diff ) <= TOLERANCE then
  716.         
  717.         return true
  718.         
  719.     else
  720.     
  721.         return false
  722.         
  723.     end if
  724.     
  725. end function
  726.  
  727. %
  728. % Brent's method uses interpolation in a variation of 
  729. % the bi-section method.
  730. %
  731. function Brent( low, high : real, var root : real ) : boolean
  732.  
  733.     const SMALL : real := 0.0000001             % epsilon
  734.     const VERY_SMALL : real := 0.0000000001     % near zero
  735.     var iter : int
  736.     var a, b, c : real
  737.     var fa, fb, fc : real
  738.     var d, e, tol : real
  739.     var small1, small2, small3 : real
  740.     var p, q, r : real
  741.     var s, xm : real
  742.  
  743.     iter := 1
  744.     a := low
  745.     b := high
  746.     c := high
  747.     fa := Fx( low )
  748.     fb := Fx( high )
  749.     fc := fb
  750.  
  751.     % check that the guesses contain the root
  752.     if fa * fb > 0 then
  753.      
  754.         return false
  755.  
  756.     end if
  757.  
  758.     % start loop to refine the guess for the root
  759.     loop
  760.     
  761.         exit when iter > MAX_ITER
  762.        
  763.         iter := iter + 1
  764.         
  765.         if fb * fc > 0 then
  766.       
  767.             c := a
  768.             fc := fa
  769.             e := b - a
  770.             d := e
  771.     
  772.         end if
  773.     
  774.         if abs(fc) < abs(fb) then
  775.       
  776.             a := b
  777.             b := c
  778.             c := a
  779.             fa := fb
  780.             fb := fc
  781.             fc := fa
  782.             
  783.         end if
  784.     
  785.         tol := 2 * SMALL * abs(b) + TOLERANCE / 2
  786.         xm := ( c - b ) / 2
  787.     
  788.         if abs( xm ) <= tol or abs( fb ) <= VERY_SMALL then
  789.  
  790.             root := b
  791.             return true
  792.  
  793.         end if
  794.     
  795.         if abs( e ) >= tol and abs( fa ) > abs( fb ) then
  796.       
  797.             % perform the inverse quadratic interpolation
  798.             s := fb / fa
  799.             if abs(a - c) <= VERY_SMALL then
  800.                 
  801.                 p := 2 * xm * s
  802.                 q := 1 - s
  803.       
  804.             else
  805.         
  806.                 q := fa / fc
  807.                 r := fb / fc
  808.                 q := s * (2 * xm * q * (q - r) - (b - a) * (r - 1))
  809.                 q := (q - 1) * (r - 1) * (s - 1)
  810.       
  811.             end if
  812.       
  813.             % determine if improved guess is inside the range
  814.             if p > 0 then 
  815.             
  816.                 q := -q
  817.  
  818.             end if
  819.       
  820.             p := abs( p )
  821.             small1 := 3 * xm * q * abs(tol * q)
  822.             small2 := abs(e * q)
  823.       
  824.             if small1 < small2 then
  825.         
  826.                 small3 := small1
  827.       
  828.             else
  829.         
  830.                 small3 := small2
  831.       
  832.             end if
  833.       
  834.             if 2 * p < small3 then
  835.         
  836.                 % interpolation successfull
  837.                 e := d
  838.                 d := p / q
  839.       
  840.             else
  841.         
  842.                 % use bisection because the 
  843.                 % interpolation did not succeed
  844.                 d := xm
  845.                 e := d
  846.       
  847.             end if
  848.     
  849.         else
  850.       
  851.             % use bisection because the range
  852.             % is slowly decreasing
  853.             d := xm
  854.             e := d
  855.     
  856.         end if
  857.     
  858.         % copy most recent guess to variable a
  859.         a := b
  860.         fa := fb
  861.         
  862.         % evaluate improved guess for the root
  863.         if abs(d) > tol then
  864.       
  865.             b := b + d
  866.     
  867.         else
  868.       
  869.             if xm > 0 then
  870.         
  871.                 b := b + abs( tol )
  872.       
  873.             else
  874.         
  875.                 b := b - abs( tol )
  876.       
  877.             end if
  878.     
  879.         end if
  880.     
  881.         fb := Fx( b )
  882.   
  883.     end loop
  884.   
  885.     return false
  886.  
  887. end function
  888.  
  889. %
  890. % This process combines the bi-section and newton techniques
  891. %
  892. function Combined( low, high : real, var root : real ) : boolean
  893.  
  894.     var iter : int
  895.     var h, diff : real
  896.  
  897.     iter := 0
  898.  
  899.     loop
  900.     
  901.         iter := iter + 1
  902.         h := 0.01 * root
  903.  
  904.         if abs( root ) < 1 then
  905.         
  906.             h := 0.01
  907.  
  908.         end if
  909.         
  910.         % calculate guess refinement
  911.         diff := 2 * h * Fx( root ) / ( Fx( root + h ) - Fx( root - h ) )
  912.                 
  913.         root := root - diff
  914.      
  915.         % check if Newton's method yields a refined guess
  916.         % outside the range (low, high)
  917.      
  918.         if root < low or root > high then
  919.        
  920.             % apply Bisection method for this iteration
  921.             root := ( low + high ) / 2
  922.        
  923.             if Fx( root ) * Fx( high ) > 0 then
  924.          
  925.                 high := root
  926.        
  927.             else
  928.          
  929.                 low  := root
  930.        
  931.             end if
  932.      
  933.         end if
  934.  
  935.         exit when iter > MAX_ITER or abs( diff ) < TOLERANCE
  936.   
  937.     end loop
  938.  
  939.   
  940.     if abs( diff ) <= TOLERANCE then
  941.  
  942.         return true
  943.  
  944.     else
  945.  
  946.         return false
  947.  
  948.     end if
  949.  
  950. end function
  951.  
  952. %
  953. % The deflating polynomial method combines a polynomial reduction
  954. % step with Newton's method.  As each (real) root is found, the
  955. % order of the polynomial to be solved is reduced.
  956. %
  957. function Deflate_polynomial( var coeff : rvector, 
  958.                              initGuess : real, 
  959.                              var roots : rvector, 
  960.                              numRoots, polyOrder : int ) : boolean
  961.   
  962.     var a b, c : rvector
  963.     var diff, z, X : real
  964.     var i, iter, n : int
  965.   
  966.     iter := 1
  967.     n := polyOrder + 1
  968.     X := initGuess
  969.     numRoots := 0
  970.   
  971.     for i := 0...n-1 do
  972.         
  973.         a[i] := coeff[i]
  974.     
  975.     end for
  976.   
  977.     loop
  978.  
  979.         exit when iter > MAX_ITER or n <= 1
  980.  
  981.         iter := iter + 1
  982.         z := X
  983.         b[n-1] := a[n-1]
  984.         c[n-1] := a[n-1]
  985.        
  986.         for decreasing i := n-2...1 do
  987.          
  988.             b[i] := a[i] + z * b[i+1]
  989.             c[i] := b[i] + z * c[i+1]
  990.        
  991.         end for
  992.        
  993.         b[0] := a[0] + z * b[1]
  994.         diff := b[0] / c[1]
  995.         X := X - diff
  996.        
  997.         if abs(diff) <= TOLERANCE then
  998.          
  999.             iter := 1              % reset iteration counter
  1000.             n := n - 1
  1001.             roots[numRoots] := X
  1002.             numRoots := numRoots + 1
  1003.          
  1004.             % update deflated roots
  1005.             for i := 0...n-1 do
  1006.            
  1007.                 a[i] := b[i + 1]
  1008.            
  1009.                 % get the last root
  1010.                 if n = 2 then
  1011.              
  1012.                     n := n - 1
  1013.                     roots[numRoots] := -a[0]
  1014.                     numRoots := numRoots + 1
  1015.            
  1016.                 end if
  1017.          
  1018.             end for
  1019.        
  1020.         end if
  1021.     
  1022.     end loop
  1023.     
  1024.     return true
  1025.     
  1026. end function
  1027.  
  1028. %
  1029. % The Lin-Bairstow method improves on the deflation method to solve 
  1030. % for the complex roots of the following polynomial:
  1031. %
  1032. %     y = coeff(0) + coeff(1) X + coeff(2) X^2 +...+ coeff(n) X^n
  1033. %
  1034. % parameters:
  1035. %
  1036. %   coeff      must be an array with at least order+1 elements.
  1037. %   roots      output array of roots
  1038. %   order      order of polynomial
  1039. %
  1040. function Lin_Bairstow( var coeff : rvector, 
  1041.                        var roots : cvector, 
  1042.                        order     : int ) : boolean
  1043.  
  1044.     const SMALL : real := 0.00000001
  1045.     var a, b, c, d : rvector
  1046.     var alfa1, alfa2 : real
  1047.     var beta1, beta2 : real
  1048.     var delta1, delta2, delta3 : real
  1049.     var i, j, k : int
  1050.     var count : int
  1051.     var n : int
  1052.     var n1 : int
  1053.     var n2 : int
  1054.  
  1055.     n := order
  1056.     n1 := n + 1
  1057.     n2 := n + 2
  1058.   
  1059.     % is the coefficient of the highest term zero?
  1060.     if abs( coeff[0] ) < SMALL then
  1061.     
  1062.         return false
  1063.  
  1064.     end if
  1065.  
  1066.     for i := 0...n do
  1067.         
  1068.         a[n1-i] := coeff[i]
  1069.   
  1070.     end for
  1071.     
  1072.     % is highest coeff not close to 1?
  1073.     if abs( a[1]-1 ) > SMALL then
  1074.      
  1075.         % adjust coefficients because a(1) != 1
  1076.         for i := 2...n1 do
  1077.        
  1078.             a[i] := a[i] / a[1]
  1079.      
  1080.         end for
  1081.      
  1082.         a[1] := 1
  1083.   
  1084.     end if
  1085.  
  1086.     % initialize root counter
  1087.     count := 0
  1088.  
  1089.     %
  1090.     % start the main Lin-Bairstow iteration loop
  1091.     % initialize the counter and guesses for the
  1092.     % coefficients of quadratic factor:
  1093.     %
  1094.     % p(x) = x^2 + alfa1 * x + beta1
  1095.     %
  1096.     loop
  1097.     
  1098.         alfa1 := 1
  1099.         beta1 := 1
  1100.  
  1101.         loop
  1102.        
  1103.             b[0] := 0
  1104.             d[0] := 0
  1105.             b[1] := 1
  1106.             d[1] := 1
  1107.  
  1108.             j := 1
  1109.             k := 0
  1110.        
  1111.             for i := 2...n1 do
  1112.          
  1113.                 b[i] := a[i] - alfa1 * b[j] - beta1 * b[k]
  1114.                 d[i] := b[i] - alfa1 * d[j] - beta1 * d[k]
  1115.                 j := j + 1
  1116.                 k := k + 1
  1117.        
  1118.             end for
  1119.        
  1120.             j := n - 1
  1121.             k := n - 2
  1122.             delta1 := d[j]^2 - ( d[n] - b[n] ) * d[k]
  1123.             alfa2 := ( b[n] * d[j] - b[n1] * d[k] ) / delta1
  1124.             beta2 := ( b[n1] * d[j] - ( d[n] - b[n] ) * b[n] ) / delta1
  1125.             alfa1 := alfa1 + alfa2
  1126.             beta1 := beta1 + beta2
  1127.             
  1128.             exit when abs( alfa2 ) < TOLERANCE and abs( beta2 ) < TOLERANCE
  1129.  
  1130.         end loop
  1131.         
  1132.         delta1 := alfa1^2 - 4 * beta1
  1133.  
  1134.         if delta1 < 0 then      % imaginary roots
  1135.        
  1136.             delta2 := sqrt( abs( delta1 ) ) / 2
  1137.             delta3 := -alfa1 / 2
  1138.  
  1139.             roots[count].re :=  delta3
  1140.             roots[count].im := +delta2
  1141.             
  1142.             roots[count+1].re :=  delta3
  1143.             roots[count+1].im := -delta2
  1144.      
  1145.         else                    % roots are real
  1146.        
  1147.             delta2 := sqrt( delta1 )
  1148.        
  1149.             roots[count].re := ( delta2 - alfa1 ) / 2
  1150.             roots[count].im := 0
  1151.  
  1152.             roots[count+1].re := ( delta2 + alfa1 ) / ( -2 )
  1153.             roots[count+1].im := 0
  1154.      
  1155.         end if
  1156.      
  1157.         % update root counter
  1158.         count := count + 2
  1159.  
  1160.         % reduce polynomial order
  1161.         n := n - 2
  1162.         n1 := n1 - 2
  1163.         n2 := n2 - 2
  1164.  
  1165.         % for n >= 2 calculate coefficients of
  1166.         %  the new polynomial
  1167.         if n >= 2 then
  1168.        
  1169.             for i := 1...n1 do
  1170.          
  1171.                 a[i] := b[i]
  1172.        
  1173.             end for
  1174.      
  1175.         end if
  1176.   
  1177.         exit when n < 2
  1178.  
  1179.     end loop
  1180.   
  1181.     if n = 1 then 
  1182.     
  1183.         % obtain last single real root
  1184.         roots[count].re := -b[2]
  1185.         roots[count].im := 0
  1186.   
  1187.     end if
  1188.  
  1189.     return true
  1190.     
  1191. end function
  1192.  
  1193. %
  1194. % This function uses Newton's method adapted for the solution of
  1195. % two simultaneous non-linear equations.
  1196. %
  1197. function Newton2functions( var rootX, rootY : real ) : boolean
  1198.  
  1199.     var Jacob : real
  1200.     var fx0, fy0 : real
  1201.     var hX, hY : real
  1202.     var diffX, diffY : real
  1203.     var fxy, fxx : real
  1204.     var fyy, fyx : real
  1205.     var X : real
  1206.     var Y : real
  1207.     var iter : int
  1208.  
  1209.     X := rootX
  1210.     Y := rootY
  1211.     iter := 1
  1212.  
  1213.     loop
  1214.      
  1215.         hX := 0.01 * rootX
  1216.         
  1217.         if abs( rootX ) < 1 then
  1218.         
  1219.             hX := 0.01
  1220.             
  1221.         end if
  1222.         
  1223.         hY := 0.01 * rootY
  1224.         
  1225.         if abs(rootY) < 1 then
  1226.         
  1227.             hY := 0.01
  1228.         
  1229.         end if
  1230.         
  1231.         fx0 := F1xy( X, Y )
  1232.         fy0 := F2xy( X, Y )
  1233.         fxx := ( F1xy( X + hX, Y ) - F1xy( X - hX, Y ) ) / 2 / hX
  1234.         fyx := ( F2xy( X + hX, Y ) - F2xy( X - hX, Y ) ) / 2 / hX
  1235.         fxy := ( F1xy( X, Y + hY ) - F1xy( X, Y - hY ) ) / 2 / hY
  1236.         fyy := ( F2xy( X, Y + hY ) - F2xy( X, Y - hY ) ) / 2 / hY
  1237.         Jacob := fxx * fyy - fxy * fyx
  1238.         diffX := ( fx0 * fyy - fy0 * fxy ) / Jacob
  1239.         diffY := ( fy0 * fxx - fx0 * fyx ) / Jacob
  1240.         X := X - diffX
  1241.         Y := Y - diffY
  1242.         iter := iter + 1
  1243.  
  1244.         exit when iter > MAX_ITER 
  1245.         exit when abs( diffX ) < TOLERANCE and abs( diffY ) < TOLERANCE
  1246.  
  1247.     end loop
  1248.  
  1249.     rootX := X
  1250.     rootY := Y
  1251.   
  1252.     if abs( diffX ) <= TOLERANCE and abs( diffY ) <= TOLERANCE then
  1253.  
  1254.         return true
  1255.  
  1256.     else
  1257.  
  1258.         return false
  1259.  
  1260.     end if
  1261.  
  1262. end function
  1263.  
  1264. %
  1265. % This function uses Newton's method adapted for the solution of
  1266. % multiple simultaneous non-linear equations.
  1267. %
  1268. function NewtonMultiRoots ( var roots : rvector, 
  1269.                             var numRoots : int, 
  1270.                             maxRoots : int ) : boolean
  1271.  
  1272.     var iter, i : int
  1273.     var h, diff : real
  1274.     var f1, f2, f3 : real
  1275.     var root : real
  1276.  
  1277.     numRoots := 0
  1278.     root := roots[0]
  1279.  
  1280.     loop
  1281.  
  1282.         iter := 0
  1283.         loop
  1284.  
  1285.             h := 0.01 * root
  1286.  
  1287.             if abs( root ) < 1 then 
  1288.                 h := 0.01
  1289.             end if
  1290.  
  1291.             f1 := Fx( root - h )
  1292.             f2 := Fx( root )
  1293.             f3 := Fx( root + h )
  1294.  
  1295.             if numRoots > 0 then
  1296.         
  1297.                 for i := 0...numRoots-1 do
  1298.           
  1299.                     f1 := f1 / ( root - h - roots[i] )
  1300.                     f2 := f2 / ( root - roots[i] )
  1301.                     f3 := f3 / ( root + h - roots[i] )
  1302.                 end for
  1303.  
  1304.             end if
  1305.             
  1306.             % calculate guess refinement
  1307.             diff := 2 * h * f2 / ( f3 - f1 )
  1308.       
  1309.             % update guess
  1310.             root := root - diff
  1311.             iter := iter + 1
  1312.  
  1313.             exit when iter > MAX_ITER or abs( diff ) <= TOLERANCE
  1314.         
  1315.         end loop
  1316.  
  1317.         if abs(diff) <= TOLERANCE then
  1318.       
  1319.             roots[numRoots] := root
  1320.             numRoots := numRoots + 1
  1321.       
  1322.             if root < 0 then
  1323.         
  1324.                 root := 0.95 * root
  1325.       
  1326.             elsif root > 0 then
  1327.         
  1328.                 root := 1.05 * root
  1329.       
  1330.             else
  1331.         
  1332.                 root := 0.05
  1333.       
  1334.             end if
  1335.     
  1336.         end if
  1337.   
  1338.         exit when iter > MAX_ITER or numRoots >= maxRoots
  1339.  
  1340.     end loop
  1341.  
  1342.  
  1343.     if numRoots > 0 then
  1344.         
  1345.         return true
  1346.   
  1347.     else
  1348.     
  1349.         return false
  1350.   
  1351.     end if
  1352.  
  1353. end function
  1354.  
  1355. %
  1356. % This function uses another adaptation of Newton's method for the 
  1357. % solution of multiple simultaneous non-linear equations.  It uses
  1358. % matrix arithmetic functions LUDecomp and LUBackSubst.
  1359. %
  1360. function NewtonSimNLE( var X : rvector, 
  1361.                        numEqns : int ) : boolean
  1362.  
  1363.     var Xdash : rvector
  1364.     var Fvector : rvector
  1365.     var index : ivector
  1366.     var Jmat : rmatrix
  1367.     var i, j : int
  1368.     var moreIter : boolean
  1369.     var iter : int
  1370.     var rowSwapFlag : int
  1371.     var h : real
  1372.     var dummy : boolean
  1373.  
  1374.     iter := 0
  1375.  
  1376.     loop
  1377.     
  1378.         iter := iter + 1
  1379.     
  1380.         % copy the values of array X into array Xdash
  1381.         for i := 0...numEqns-1 do
  1382.             
  1383.             Xdash[i] := X[i]
  1384.         
  1385.         end for
  1386.     
  1387.         % calculate the array of function values
  1388.         for i := 0...numEqns-1 do
  1389.         
  1390.             Fvector[i] := Snle( X, i )
  1391.         
  1392.         end for
  1393.     
  1394.         % calculate the Jmat matrix
  1395.         for i := 0...numEqns-1 do
  1396.         
  1397.             for j := 0...numEqns-1 do
  1398.             
  1399.                 % calculate increment in variable number j
  1400.                 if abs( X[j] ) > 1 then
  1401.  
  1402.                     h := 0.01 * X[j]
  1403.  
  1404.                 else
  1405.  
  1406.                     h := 0.01
  1407.  
  1408.                 end if
  1409.                 
  1410.                 Xdash[j] := Xdash[j] + h
  1411.                 Jmat[i,j] := ( Snle( Xdash, i ) - Fvector[i] ) / h
  1412.         
  1413.                 % restore incremented value
  1414.                 Xdash[j] := X[j]
  1415.  
  1416.             end for % j
  1417.  
  1418.         end for % i
  1419.     
  1420.         % solve for the guess refinement vector
  1421.         dummy := LUDecomp( Jmat, index, numEqns, rowSwapFlag )
  1422.         LUBackSubst( Jmat, index, numEqns, Fvector )
  1423.     
  1424.         % clear the more-iteration flag
  1425.         moreIter := false
  1426.         
  1427.         % update guess and test for convergence
  1428.         for i := 0...numEqns-1 do
  1429.         
  1430.             X[i] := X[i] - Fvector[i]
  1431.             
  1432.             if abs( Fvector[i] ) > TOLERANCE then 
  1433.             
  1434.                 moreIter := true
  1435.  
  1436.             end if
  1437.             
  1438.         end for
  1439.     
  1440.         % check iteration limit
  1441.         if moreIter then
  1442.             
  1443.             if iter > MAX_ITER then
  1444.         
  1445.                 moreIter := false
  1446.       
  1447.             else
  1448.         
  1449.                 moreIter := true
  1450.       
  1451.             end if
  1452.     
  1453.         end if
  1454.  
  1455.         exit when not moreIter
  1456.  
  1457.     end loop
  1458.  
  1459.     return not moreIter
  1460.  
  1461. end function
  1462.  
  1463. %
  1464. % This function performs LU decomposition of a matrix of real values.
  1465. %
  1466. function LUDecomp( var A : rmatrix, 
  1467.                    var Index : ivector, 
  1468.                    numRows : int, 
  1469.                    rowSwapFlag : int ) : boolean
  1470.  
  1471.     var i, j : int
  1472.     var k, iMax : int
  1473.     var large, sum : real
  1474.     var z, z2 : real
  1475.     var scaleVect : rvector
  1476.  
  1477.  
  1478.     % initialize row interchange flag
  1479.     rowSwapFlag := 1
  1480.   
  1481.     % loop to obtain the scaling element
  1482.     for i := 0...numRows-1 do
  1483.     
  1484.         large := 0
  1485.         
  1486.         for j := 0...numRows-1 do
  1487.       
  1488.             z2 := abs( A[i,j] )
  1489.       
  1490.             if z2 > large then 
  1491.             
  1492.                 large := z2
  1493.  
  1494.             end if
  1495.     
  1496.         end for % j
  1497.         
  1498.         % no non-zero large value? then exit with an error code
  1499.         if large = 0 then
  1500.       
  1501.             return false
  1502.     
  1503.         end if
  1504.     
  1505.         scaleVect[i] := 1 / large
  1506.   
  1507.     end for % i
  1508.   
  1509.     for j := 0...numRows-1 do
  1510.     
  1511.         for i := 0...j-1 do
  1512.       
  1513.             sum := A[i,j]
  1514.       
  1515.             for k := 0...i-1 do
  1516.  
  1517.                 sum := sum - A[i,k] * A[k,j]
  1518.       
  1519.             end for
  1520.       
  1521.             A[i,j] := sum
  1522.     
  1523.         end for
  1524.     
  1525.         large := 0
  1526.     
  1527.         for i := j...numRows-1 do
  1528.       
  1529.             sum := A[i,j]
  1530.       
  1531.             for k := 0...j-1 do
  1532.  
  1533.                 sum := sum - A[i,k] * A[k,j]
  1534.       
  1535.             end for
  1536.       
  1537.             A[i,j] := sum
  1538.             z := scaleVect[i] * abs( sum )
  1539.       
  1540.             if z >= large then
  1541.  
  1542.                 large := z
  1543.                 iMax := i
  1544.       
  1545.             end if
  1546.     
  1547.         end for % i
  1548.     
  1549.         if j ~= iMax then
  1550.       
  1551.             for k := 0...numRows-1 do
  1552.  
  1553.                 z := A[iMax,k]
  1554.                 A[iMax,k] := A[j,k]
  1555.                 A[j,k] := z
  1556.       
  1557.             end for % k
  1558.       
  1559.             rowSwapFlag := -1 * rowSwapFlag
  1560.             scaleVect[iMax] := scaleVect[j]
  1561.     
  1562.         end if
  1563.     
  1564.         Index[j] := iMax
  1565.     
  1566.         if A[j,j] = 0 then
  1567.       
  1568.             A[j,j] := MATVECT_EPSILON
  1569.         
  1570.         end if
  1571.     
  1572.         if j ~= numRows then
  1573.       
  1574.             z := 1 / A[j,j]
  1575.       
  1576.             for i := j + 1...numRows-1 do
  1577.  
  1578.                 A[i,j] := A[i,j] * z
  1579.       
  1580.             end for % i
  1581.     
  1582.         end if
  1583.   
  1584.     end for % j
  1585.   
  1586.     return true
  1587.  
  1588. end function
  1589.  
  1590. %
  1591. % This function uses the LU decomposition of a matrix to solve:
  1592. %
  1593. %           A x = b
  1594. %
  1595. % the solution for x is returned in b.
  1596. %
  1597. procedure LUBackSubst( var A : rmatrix,
  1598.                        var Index : ivector, 
  1599.                        numRows : int, 
  1600.                        var b : rvector )
  1601.  
  1602.     var i, j : int
  1603.     var idx, k : int
  1604.     var sum : real
  1605.  
  1606.     k := -1
  1607.   
  1608.     for i := 0...numRows-1 do
  1609.     
  1610.         idx := Index[i]
  1611.         sum := b[idx]
  1612.         b[idx] := b[i]
  1613.     
  1614.         if k > -1 then
  1615.       
  1616.             for j := k...i-1 do
  1617.  
  1618.                 sum := sum - A[i,j] * b[j]
  1619.                 
  1620.             end for % j
  1621.     
  1622.         elsif sum ~= 0 then
  1623.       
  1624.             k := i
  1625.     
  1626.         end if
  1627.     
  1628.         b[i] := sum
  1629.   
  1630.     end for % i
  1631.   
  1632.     for decreasing i := numRows-1...0 do
  1633.     
  1634.         sum := b[i]
  1635.     
  1636.         for j := i + 1...numRows-1 do
  1637.       
  1638.             sum := sum - A[i,j] * b[j]
  1639.     
  1640.         end for % j
  1641.     
  1642.         b[i] := sum / A[i,i]
  1643.   
  1644.     end for % i
  1645.  
  1646. end procedure
  1647.  
  1648. %
  1649. % returns the absolute value of the argument
  1650. %
  1651. function abs( x : real ) : real
  1652.  
  1653.     if x < 0.0 then
  1654.         x := -x
  1655.     end if
  1656.  
  1657.     return x
  1658.  
  1659. end function
  1660.  
  1661. %
  1662. % returns a complex number as a string
  1663. %
  1664. function cstr( var c : complex ) : string
  1665.  
  1666.     var s : string
  1667.     var re, im : real
  1668.  
  1669.     re := c.re
  1670.     im := c.im
  1671.  
  1672.     if im >= 0.0 then
  1673.         s := frealstr(re,14,9 ) & " +" & frealstr(im,12,9 ) & "j"
  1674.     else
  1675.         im := -im
  1676.         s := frealstr(re,14,9 ) & " -" & frealstr(im,12,9 ) & "j"
  1677.     end if
  1678.  
  1679.     return s
  1680.  
  1681. end function